class MyPromise {

    constructor(executor) {
        //状态有三种 pending fulfilled rejected
        this.state = 'pending'
        //成功的值
        this.value = undefined
        //失败的原因
        this.reason = undefined
        //成功回调数组
        this.resolveCallbacks = []
        //失败回调数组
        this.rejectCallbacks = []
        let resolve = (value) => {
            if (this.state === 'pending') {
                this.value = value
                // resolve调用后，state转化为成功态
                this.state = 'fulfilled';
                this.resolveCallbacks.forEach(fn => fn())
            }
        }
        let reject = (reason) => {
            if (this.state === 'pending') {
                this.reason = reason
                // resolve调用后，state转化为成功态
                this.state = 'rejected';
                this.rejectCallbacks.forEach(fn => fn())
            }
        }
        try {
            executor(resolve, reject)
        } catch (error) {
            reject(error)
        }

    }

    then(onFulfill, onReject) {

        // onFulfilled如果不是函数，就忽略onFulfilled，直接返回value
        onFulfill = typeof onFulfill === 'function' ? onFulfill : value => value;
        // onRejected如果不是函数，就忽略onRejected，直接扔出错误
        onReject = typeof onReject === 'function' ? onReject : err => { throw err };

        let promise2 = new MyPromise((resolve, reject) => {

            if (this.state === 'fulfilled') {
                setTimeout(() => {
                    try {
                        let x = onFulfill(this.value)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)

            }
            if (this.state === 'rejected') {
                setTimeout(() => {
                    try {
                        let x = onReject(this.reason)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)

            }
            //解决settimeout 
            if (this.state === 'pending') {
                this.resolveCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onFulfill(this.value)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)

                })

                this.rejectCallbacks.push(() => {

                    setTimeout(() => {
                        try {
                            let x = onReject(this.reason)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                })
            }
        })
        return promise2
    }

    resolvePromise(promise2, x, resolve, reject) {
        // 循环引用报错
        if (x === promise2) {
            // reject报错
            return reject(new TypeError('Chaining cycle detected for promise'));
        }
        // 防止多次调用
        let called;
        // x不是null 且x是对象或者函数
        if (x != null && (typeof x === 'object' || typeof x === 'function')) {
            try {
                // A+规定，声明then = x的then方法
                let then = x.then;
                // 如果then是函数，就默认是promise了
                if (typeof then === 'function') {
                    // 就让then执行 第一个参数是this   后面是成功的回调 和 失败的回调
                    then.call(x, y => {
                        // 成功和失败只能调用一个
                        if (called) return;
                        called = true;
                        // resolve的结果依旧是promise 那就继续解析
                        resolvePromise(promise2, y, resolve, reject);
                    }, err => {
                        // 成功和失败只能调用一个
                        if (called) return;
                        called = true;
                        reject(err);// 失败了就失败了
                    })
                } else {
                    resolve(x); // 直接成功即可
                }
            } catch (e) {
                // 也属于失败
                if (called) return;
                called = true;
                // 取then出错了那就不要在继续执行了
                reject(e);
            }
        } else {
            resolve(x);
        }
    }
}